// Emacs style mode select   -*- C++ -*-
//-----------------------------------------------------------------------------
//
// Copyright (C) 1993-1996 by id Software, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// DESCRIPTION:  none
//      Implements special effects:
//      Texture animation, height or lighting changes
//       according to adjacent sectors, respective
//       utility functions, etc.
//
//-----------------------------------------------------------------------------

#ifndef __P_SPEC__
#define __P_SPEC__

//
// End-level timer (-TIMER option)
//
extern  boolean levelTimer;
extern  int     levelTimeCount;

//      Define values for map objects
#define MO_TELEPORTMAN          14

// at game start
void    P_InitPicAnims (void);

// at map load
void    P_SpawnSpecials (void);

// every tic
void    P_UpdateSpecials (void);

// when needed
boolean
P_UseSpecialLine
( mobj_t*       thing,
  line_t*       line,
  int           side );

void
P_ShootSpecialLine
( mobj_t*       thing,
  line_t*       line );

void
P_CrossSpecialLine
( int           linenum,
  int           side,
  mobj_t*       thing );

void    P_PlayerInSpecialSector (player_t* player);

int
twoSided
( int           sector,
  int           line );

sector_t*
getSector
( int           currentSector,
  int           line,
  int           side );

side_t*
getSide
( int           currentSector,
  int           line,
  int           side );

fixed_t P_FindLowestFloorSurrounding(sector_t* sec);
fixed_t P_FindHighestFloorSurrounding(sector_t* sec);

fixed_t
P_FindNextHighestFloor
( sector_t*     sec,
  int           currentheight );

fixed_t P_FindLowestCeilingSurrounding(sector_t* sec);
fixed_t P_FindHighestCeilingSurrounding(sector_t* sec);

int
P_FindSectorFromLineTag
( line_t*       line,
  int           start );

int
P_FindMinSurroundingLight
( sector_t*     sector,
  int           max );

sector_t*
getNextSector
( line_t*       line,
  sector_t*     sec );

//
// SPECIAL
//
int EV_DoDonut(line_t* line);

//
// P_LIGHTS
//
typedef struct
{
    thinker_t   thinker;
    sector_t*   sector;
    int         count;
    int         maxlight;
    int         minlight;

} fireflicker_t;

typedef struct
{
    thinker_t   thinker;
    sector_t*   sector;
    int         count;
    int         maxlight;
    int         minlight;
    int         maxtime;
    int         mintime;

} lightflash_t;

typedef struct
{
    thinker_t   thinker;
    sector_t*   sector;
    int         count;
    int         minlight;
    int         maxlight;
    int         darktime;
    int         brighttime;

} strobe_t;

typedef struct
{
    thinker_t   thinker;
    sector_t*   sector;
    int         minlight;
    int         maxlight;
    int         direction;

} glow_t;

#define GLOWSPEED                       8
#define STROBEBRIGHT            5
#define FASTDARK                        15
#define SLOWDARK                        35

void    P_SpawnFireFlicker (sector_t* sector);
void    T_LightFlash (lightflash_t* flash);
void    P_SpawnLightFlash (sector_t* sector);
void    T_StrobeFlash (strobe_t* flash);

void
P_SpawnStrobeFlash
( sector_t*     sector,
  int           fastOrSlow,
  int           inSync );

void    EV_StartLightStrobing(line_t* line);
void    EV_TurnTagLightsOff(line_t* line);

void
EV_LightTurnOn
( line_t*       line,
  int           bright );

void    T_Glow(glow_t* g);
void    P_SpawnGlowingLight(sector_t* sector);

//
// P_SWITCH
//
typedef struct
{
    char        name1[9];
    char        name2[9];
    short       episode;

} switchlist_t;

typedef enum
{
    top,
    middle,
    bottom

} bwhere_e;

typedef struct
{
    line_t*     line;
    bwhere_e    where;
    int         btexture;
    int         btimer;
    mobj_t*     soundorg;

} button_t;

 // max # of wall switches in a level
#define MAXSWITCHES             50

 // 4 players, 4 buttons each at once, max.
#define MAXBUTTONS              16

 // 1 second, in ticks.
#define BUTTONTIME      35

extern button_t buttonlist[MAXBUTTONS];

void
P_ChangeSwitchTexture
( line_t*       line,
  int           useAgain );

void P_InitSwitchList(void);

//
// P_PLATS
//
typedef enum
{
    up,
    down,
    waiting,
    in_stasis

} plat_e;

typedef enum
{
    perpetualRaise,
    downWaitUpStay,
    raiseAndChange,
    raiseToNearestAndChange,
    blazeDWUS

} plattype_e;

typedef struct
{
    thinker_t   thinker;
    sector_t*   sector;
    fixed_t     speed;
    fixed_t     low;
    fixed_t     high;
    int         wait;
    int         count;
    plat_e      status;
    plat_e      oldstatus;
    boolean     crush;
    int         tag;
    plattype_e  type;

} plat_t;

#define PLATWAIT                3
#define PLATSPEED               FRACUNIT
#define MAXPLATS                30

extern plat_t*  activeplats[MAXPLATS];

void    T_PlatRaise(plat_t*     plat);

int
EV_DoPlat
( line_t*       line,
  plattype_e    type,
  int           amount );

void    P_AddActivePlat(plat_t* plat);
void    P_RemoveActivePlat(plat_t* plat);
void    EV_StopPlat(line_t* line);
void    P_ActivateInStasis(int tag);

//
// P_DOORS
//
typedef enum
{
    normal,
    close30ThenOpen,
    close,
    open,
    raiseIn5Mins,
    blazeRaise,
    blazeOpen,
    blazeClose

} vldoor_e;

typedef struct
{
    thinker_t   thinker;
    vldoor_e    type;
    sector_t*   sector;
    fixed_t     topheight;
    fixed_t     speed;

    // 1 = up, 0 = waiting at top, -1 = down
    int             direction;

    // tics to wait at the top
    int             topwait;
    // (keep in case a door going down is reset)
    // when it reaches 0, start going down
    int             topcountdown;

} vldoor_t;

#define VDOORSPEED              FRACUNIT*2
#define VDOORWAIT               150

void
EV_VerticalDoor
( line_t*       line,
  mobj_t*       thing );

int
EV_DoDoor
( line_t*       line,
  vldoor_e      type );

int
EV_DoLockedDoor
( line_t*       line,
  vldoor_e      type,
  mobj_t*       thing );

void    T_VerticalDoor (vldoor_t* door);
void    P_SpawnDoorCloseIn30 (sector_t* sec);

void
P_SpawnDoorRaiseIn5Mins
( sector_t*     sec,
  int           secnum );

#if 0 // UNUSED
//
//      Sliding doors...
//
typedef enum
{
    sd_opening,
    sd_waiting,
    sd_closing

} sd_e;

typedef enum
{
    sdt_openOnly,
    sdt_closeOnly,
    sdt_openAndClose

} sdt_e;

typedef struct
{
    thinker_t   thinker;
    sdt_e       type;
    line_t*     line;
    int         frame;
    int         whichDoorIndex;
    int         timer;
    sector_t*   frontsector;
    sector_t*   backsector;
    sd_e         status;

} slidedoor_t;

typedef struct
{
    char        frontFrame1[9];
    char        frontFrame2[9];
    char        frontFrame3[9];
    char        frontFrame4[9];
    char        backFrame1[9];
    char        backFrame2[9];
    char        backFrame3[9];
    char        backFrame4[9];

} slidename_t;

typedef struct
{
    int             frontFrames[4];
    int             backFrames[4];

} slideframe_t;

// how many frames of animation
#define SNUMFRAMES              4

#define SDOORWAIT               35*3
#define SWAITTICS               4

// how many diff. types of anims
#define MAXSLIDEDOORS   5

void P_InitSlidingDoorFrames(void);

void
EV_SlidingDoor
( line_t*       line,
  mobj_t*       thing );
#endif

//
// P_CEILNG
//
typedef enum
{
    lowerToFloor,
    raiseToHighest,
    lowerAndCrush,
    crushAndRaise,
    fastCrushAndRaise,
    silentCrushAndRaise

} ceiling_e;

typedef struct
{
    thinker_t   thinker;
    ceiling_e   type;
    sector_t*   sector;
    fixed_t     bottomheight;
    fixed_t     topheight;
    fixed_t     speed;
    boolean     crush;

    // 1 = up, 0 = waiting, -1 = down
    int         direction;

    // ID
    int         tag;
    int         olddirection;

} ceiling_t;

#define CEILSPEED               FRACUNIT
#define CEILWAIT                150
#define MAXCEILINGS             30

extern ceiling_t*       activeceilings[MAXCEILINGS];

int
EV_DoCeiling
( line_t*       line,
  ceiling_e     type );

void    T_MoveCeiling (ceiling_t* ceiling);
void    P_AddActiveCeiling(ceiling_t* c);
void    P_RemoveActiveCeiling(ceiling_t* c);
int     EV_CeilingCrushStop(line_t* line);
void    P_ActivateInStasisCeiling(line_t* line);

//
// P_FLOOR
//
typedef enum
{
    // lower floor to highest surrounding floor
    lowerFloor,

    // lower floor to lowest surrounding floor
    lowerFloorToLowest,

    // lower floor to highest surrounding floor VERY FAST
    turboLower,

    // raise floor to lowest surrounding CEILING
    raiseFloor,

    // raise floor to next highest surrounding floor
    raiseFloorToNearest,

    // raise floor to shortest height texture around it
    raiseToTexture,

    // lower floor to lowest surrounding floor
    //  and change floorpic
    lowerAndChange,

    raiseFloor24,
    raiseFloor24AndChange,
    raiseFloorCrush,

     // raise to next highest floor, turbo-speed
    raiseFloorTurbo,
    donutRaise,
    raiseFloor512

} floor_e;

typedef enum
{
    build8,     // slowly build by 8
    turbo16     // quickly build by 16

} stair_e;

typedef struct
{
    thinker_t   thinker;
    floor_e     type;
    boolean     crush;
    sector_t*   sector;
    int         direction;
    int         newspecial;
    short       texture;
    fixed_t     floordestheight;
    fixed_t     speed;

} floormove_t;

#define FLOORSPEED              FRACUNIT

typedef enum
{
    ok,
    crushed,
    pastdest

} result_e;

result_e
T_MovePlane
( sector_t*     sector,
  fixed_t       speed,
  fixed_t       dest,
  boolean       crush,
  int           floorOrCeiling,
  int           direction );

int
EV_BuildStairs
( line_t*       line,
  stair_e       type );

int
EV_DoFloor
( line_t*       line,
  floor_e       floortype );

void T_MoveFloor( floormove_t* floor);

//
// P_TELEPT
//
int
EV_Teleport
( line_t*       line,
  int           side,
  mobj_t*       thing );

#endif  // __P_SPEC__
